package com.youlu.campus.web.user.controller;

import com.youlu.campus.base.exception.BusinessException;

import com.youlu.campus.common.utils.SM2CryptUtils;
import com.youlu.campus.entity.*;
import com.youlu.campus.entity.VO.req.CheckMobileVO;
import com.youlu.campus.entity.VO.res.VisitorUserInfoRes;
import com.youlu.campus.service.activity.ActivityService;
import com.youlu.campus.service.activity.UserParticipateActivityInfoService;
import com.youlu.campus.service.platform.PointPlatformConfigService;
import com.youlu.campus.service.security.SecurityIpLimitService;
import com.youlu.campus.service.visitor.VisitorUserService;
import com.youlu.campus.service.wechat.WechatAuthBlackListService;
import com.youlu.campus.web.common.base.RequestContext;
import com.youlu.campus.web.ca.service.UserCaInfoService;
import com.youlu.campus.web.user.dto.request.UserHomeRequest;
import com.youlu.campus.web.user.dto.request.UserInfoRequest;
import com.youlu.campus.web.user.service.UserService;
import com.youlu.campus.web.common.utils.CommonUtils;
import com.yuelin.infrastructure.quantum.common.QResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.Date;
import java.util.Objects;

/**
 * 用户控制器
 * 处理用户信息查询、完善、手机号验证、验证码发送及用户其他信息修改等操作
 *
 * @author: zhuhuaiqi
 * @date: 2020/8/13 13:36
 */
@Slf4j
@RestController
public class UserController {

    @Autowired
    private UserService userService;
    @Autowired
    private VisitorUserService visitorUserService;
    @Autowired
    private ActivityService activityService;
    @Autowired
    private SecurityIpLimitService securityIpLimitService;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private PointPlatformConfigService pointPlatformConfigService;
    @Autowired
    private UserParticipateActivityInfoService upService;
    @Autowired
    private WechatAuthBlackListService wechatAuthBlackListService;

    /**
     * 获取用户信息
     * 我的页面展示的用户基本信息，包含志愿者时长等
     * @return 用户信息详情
     */
    @GetMapping("/mini-app/user/info")
    public QResult getUserInfo() {
        VisitorUserInfoRes res = visitorUserService.getVisitorUerInfo(RequestContext.getUserId(), RequestContext.getCurUser());
        if (Objects.nonNull(res)) {
            Integer duration = activityService.getVolunteerDuration(RequestContext.getUserId());
            res.setVolunteerDutaion(duration);
        }
        PointPlatformConfig pointConfig = pointPlatformConfigService.find();
        res.setHasShare(pointConfig.getHasShare());
        return QResult.success(res);
    }

    /**
     * 获取用户详细信息
     * 个人主页展示的用户信息，支持查看自己或他人的信息（默认查看自己）
     * @param request 用户主页请求参数，可指定查看的用户ID
     * @return 用户详细信息
     */
    @PostMapping("/mini-app/user/info")
    public QResult userInfo(@RequestBody UserHomeRequest request) {
        if (Objects.isNull(request)) {
            request = new UserHomeRequest();
        }
        request.setUserId(RequestContext.getUserId());
        return QResult.success(userService.userInfo(request));
    }

    /**
     * 完善用户信息
     * 用户补充或修改个人信息
     * @param request 用户信息请求参数，包含需要完善的信息
     * @return 信息完善结果
     */
    @PostMapping("/mini-app/user/perfect")
    public QResult userInfoPerfect(@RequestBody @Valid UserInfoRequest request) {
        request.setPlatform(RequestContext.getCurPlatform());
        return QResult.success(userService.userInfoPerfect(request));
    }

    /**
     * 验证手机号
     * 验证用户输入的手机号及验证码是否正确
     * @param req 手机号验证请求参数，包含手机号和验证码
     * @return 验证结果
     */
    @PostMapping("/mini-app/user/check-mobile")
    public QResult checkMobile(@RequestBody @Valid CheckMobileVO req) {
        req.setUserPO(RequestContext.getCurUser());
        req.setPaltform(RequestContext.getCurPlatform());
        return QResult.success(userService.checkMobile(req));
    }

    /**
     * 发送验证码
     * 向用户手机号发送验证码，用于手机号验证等场景
     * @param req 验证码发送请求参数，包含手机号等信息
     * @param request HTTP请求对象，用于获取客户端IP
     * @return 验证码发送结果
     */
    @PostMapping("/mini-app/user/send-sms")
    public QResult sendSms(@RequestBody @Valid CheckMobileVO req, HttpServletRequest request) {
        req.setUserId(RequestContext.getUserId());
        boolean saiCheck = checkSignature(req, request.getHeader("systemAppId"));
        if (!saiCheck) {
            return QResult.fail("该手机号存在异常操作，请联系客服反馈处理！");
        }
        req.setUserPO(RequestContext.getCurUser());
        try {
            String ip = CommonUtils.getRemoteIp(request);
            log.info(":>>> 访问的IP:{}", ip);
            if (Boolean.TRUE.equals(req.getCheckDuplicateSignIn())) {
                boolean joined = upService.joined(req.getActivityId(), req.getMobile());
                if (joined) {
                    log.info(":>>> 用户已经报名活动:{},{}，验证码不需要",req.getActivityId(), req.getMobile());
                }
            }
            boolean limit = securityIpLimitService.limited(RequestContext.getUserId(), req.getMobile());
            if (limit) {
                log.error(":>>> IP非法IP");
                throw new BusinessException("非法IP请求:" + ip);
            }
            if (securityIpLimitService.exist(ip)) {
                securityIpLimitService.incre(ip, 1L);
            } else {
                SecurityIpLimit s = new SecurityIpLimit();
                s.setIp(ip);
                s.setNum(1L);
                s.setCreatedTime(new Date());
                securityIpLimitService.create(s);
            }
            SmsSendRecord smsSendRecord = new SmsSendRecord();
            smsSendRecord.setActivityId(req.getActivityId());
            smsSendRecord.setIp(ip);
            smsSendRecord.setMobile(req.getMobile());
            smsSendRecord.setUserId(RequestContext.getUserId());
            smsSendRecord.setCreatedTime(new Date());
            smsSendRecord.setNum(1L);
            mongoTemplate.insert(smsSendRecord);
        } catch (BusinessException b) {
            log.error(":>>> 业务异常:{}", b);
            throw b;
        } catch (Exception e) {
            log.error(":>>> 验证码异常:{}", e);
        }
        ActivityInfo activityInfo = null;
        if (StringUtils.isNotBlank(req.getActivityId())) {
            activityInfo = activityService.findOne(req.getActivityId());
        }
        if (Objects.isNull(activityInfo) || StringUtils.isBlank(activityInfo.getSmsSign())) {
            log.error(":>>> 活动信息不存在,或无配置短信签名");
            req.setSign("国青实践");
        } else {
            req.setSign(activityInfo.getSmsSign());
        }
        return QResult.success(userService.sendSms(req));
    }

    /**
     * 公开接口发送验证码
     * 无需登录即可发送验证码，用于公开场景下的手机号验证
     * @param req 验证码发送请求参数，包含手机号等信息
     * @param request HTTP请求对象，用于获取客户端IP
     * @return 验证码发送结果
     */
    @PostMapping("/public/user/send-sms")
    public QResult sendPublicSms(@RequestBody @Valid CheckMobileVO req, HttpServletRequest request) {
        try {
            String ip = CommonUtils.getRemoteIp(request);
            log.info(":>>> 访问的IP:{}", ip);
            boolean limit = securityIpLimitService.limited("", req.getMobile());
            if (limit) {
                log.error(":>>> IP非法IP");
                throw new BusinessException("非法IP请求:" + ip);
            }
            if (securityIpLimitService.exist(ip)) {
                securityIpLimitService.incre(ip, 1L);
            } else {
                SecurityIpLimit s = new SecurityIpLimit();
                s.setIp(ip);
                s.setNum(1L);
                s.setCreatedTime(new Date());
                securityIpLimitService.create(s);
            }
            SmsSendRecord smsSendRecord = new SmsSendRecord();
            smsSendRecord.setActivityId(req.getActivityId());
            smsSendRecord.setIp(ip);
            smsSendRecord.setMobile(req.getMobile());
            smsSendRecord.setCreatedTime(new Date());
            smsSendRecord.setNum(1L);
            mongoTemplate.insert(smsSendRecord);
        } catch (BusinessException b) {
            throw b;
        } catch (Exception e) {
            log.error(":>>> 验证码异常:{}", e);
        }
        ActivityInfo activityInfo = null;
        if (StringUtils.isNotBlank(req.getActivityId())) {
            activityInfo = activityService.findOne(req.getActivityId());
        }
        if (Objects.isNull(activityInfo) || StringUtils.isBlank(activityInfo.getSmsSign())) {
            log.error(":>>> 活动信息不存在,或无配置短信签名");
            req.setSign("赞我");
        } else {
            req.setSign(activityInfo.getSmsSign());
        }
        return QResult.success(userService.sendSms(req));
    }

    /**
     * 修改用户其他信息
     * 更新用户的附加信息，如偏好设置等
     * @param request 用户其他信息请求参数
     * @return 信息修改结果
     */
    @PostMapping("/mini-app/user/update-other-info")
    public QResult updateOtherInfo(@RequestBody @Valid UserOtherInfo request) {
        request.setUserId(RequestContext.getUserId());
        request.setOpenId(RequestContext.getCurUser().getOpenId());
        request.setAppId(RequestContext.getCurUser().getAppId());
        return QResult.success(userService.updateUserInfo(request, RequestContext.getCurPlatform()));
    }

    /**
     * 检查登录用户短信签名
     * 验证登录用户发送短信请求的签名合法性
     * @param req 验证码发送请求参数
     * @param sai 系统应用ID
     * @return 签名验证结果
     */
    private boolean checkSignature(CheckMobileVO req, String sai) {
        WechatAuthBlackList we = wechatAuthBlackListService.findBySysAppId(sai);
        if (Objects.isNull(we)) {
            log.error(":>>> 系统应用sai:{} 没有配置",sai);
            return false;
        }
        //签名: mobile&userId&timestamp
        try {
            final String privatekey=we.getPrivatekey();
            String mobile = SM2CryptUtils.decrypt(req.getMobile(), privatekey);
            String timestamp=SM2CryptUtils.decrypt(req.getTimestamp(), privatekey);
            String oSignature = mobile + "&" + req.getUserId() + "&" +timestamp;
            String signature = SM2CryptUtils.decrypt(req.getSignature(), privatekey);
            if (oSignature.equals(signature)) {
                req.setMobile(mobile);
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error(":>>> 验证短信签名失败,系统异常:{}", e);
            return false;
        }
    }

    /**
     * 检查匿名用户短信签名
     * 验证匿名用户发送短信请求的签名合法性
     * @param req 验证码发送请求参数
     * @param sai 系统应用ID
     * @return 签名验证结果
     */
    private boolean checkAnonymousSignature(CheckMobileVO req, String sai) {
        WechatAuthBlackList we = wechatAuthBlackListService.findBySysAppId(sai);
        if (Objects.isNull(we)) {
            log.error(":>>> 系统应用sai:{} 没有配置",sai);
            return false;
        }
        //签名: mobile&userId&timestamp
        try {
            final String privatekey = we.getPrivatekey();
            String mobile = SM2CryptUtils.decrypt(req.getMobile(), privatekey);
            String timestamp=SM2CryptUtils.decrypt(req.getTimestamp(), privatekey);
            String oSignature = mobile + "&" + timestamp;
            String signature = SM2CryptUtils.decrypt(req.getSignature(), privatekey);
            log.error(":>>> oSignature:{},signature:{},是否相等:{}",oSignature,
                    signature,oSignature.equals(signature));
            if (oSignature.equals(signature)) {
                req.setMobile(mobile);
                return true;
            }
            return false;
        } catch (Exception e) {
            log.error(":>>> 验证匿名短信签名失败,系统异常:{}", e);
            return false;
        }
    }

}